#include "HttpServer.hpp"
#include <string>
#include <vector>
#include <memory>
#include "Util.hpp"

const std::string SEP = "\r\n"; //默认报头分隔符
const std::string defaulhomepage = "index.html"; //默认网页
const std::string webroot = "./Webroot"; //web根目录
const std::string page_404 = "./Webroot/err_404.html"; //404页面

class Request
{
public:
    Request():_path(webroot) {}
    ~Request(){}

    void Print()
    {
        std::cout<<"method:"<<_method<<" url:"<<_url<<" version:"<<_vers<<" path:"<<_path<<std::endl;
        //for(const auto& x:_body) std::cout<<x<<std::endl;
        std::cout<<_payload<<std::endl;
    }


    std::string _method; //请求方法
    std::string _url; //请求资源路径
    std::string _path; //资源在服务器上的路径
    std::string _vers; //HTTP版本
    std::string _suffix; //资源类型
    std::vector<std::string> _body; //KV键值对
    std::string _payload; //有效载荷
};

static void usage(const char* port)
{
    std::cout<<"USAGE:\n\t"<<port<<" serverip\n"<<std::endl;
}

//分割报头内容
Request Deserialize(std::string& message)
{
    Request req;
    //1.分割第一行
    std::string line = Util::ReadOneLine(message, SEP);

    //2.将第一行的内容分割
    Util::ParseRequestLine(line, &req._method, &req._url, &req._vers);

    //获取KV
    while(!message.empty()) 
    { 
        line = Util::ReadOneLine(message, SEP);
        if(line.size() == 0) break; //返回空串表示报头结束
        req._body.push_back(line); 
    }

    req._payload = message; //填充有效载荷

    if(req._url == "/") req._path += req._url + defaulhomepage;
    else req._path += req._url;

    auto pos = req._path.rfind(".");
    if (pos == std::string::npos)
        req._suffix = ".html";
    else
        req._suffix = req._path.substr(pos); //获取 . 后的资源类型
    
    return req;
}

std::string GetContentType(const std::string &suffix)
{
    std::string content_type = "Content-Type: ";
    if (suffix == ".html" || suffix == ".htm")
        content_type + "text/html";
    else if (suffix == ".css")
        content_type += "text/css";
    else if (suffix == ".js")
        content_type += "application/x-javascript";
    else if (suffix == ".png")
        content_type += "image/png";
    else if (suffix == ".jpg" || suffix == ".jpeg")
        content_type += "image/jpeg";
    else
    {
    }
    return content_type + SEP;
}


//std::unordered_map<int, Session*> sessions;

//保存用户信息 形成Cookie
// class Session // redis -> Session
// {
// public:
//     std::string name; //用户名
//     std::string passwd; //用户密码
//     uint64_t loginTime; //登录时间
//     // 用户的其他信息
//     int status; //状态
//     int fd; //存储的文件描述符
//     int sesisonid; //对应的随机数id
// };



// bool Login(std::string &user) //未完善 思想:通过分割出的user信息，存储用户登录信息，返回cookie(相对于服务器存储信息的随机数)
// {
//     // post-> 正文包含账号密码
//     //分割用户名和密码
//     std::string name;
//     std::string passwd;

//     if(check(name, passwd)) //检查是否已存在
//     {
//         Session* session = new Session(name,passwd,...); //构造session对象存储用户信息
//         int random = rand(); //可以通过MD5等算法生成随机种子 使用Cookie传递过去而不将用户信息保存在客户端本地
//         sessions.insert(std::pair<int, Session*>(random, session)); //用户和cookie随机数种子存入服务器 下次通过用户的cookie种子在服务器中查找是否存在登录信息
//     }
//        return true;
// }

std::string HttpFunc(std::string& request)
{
    //1.反序列化 分析请求
    Request req = Deserialize(request);
    req.Print();

    //2.使用请求
    std::string Body;
    std::string response;
    if(Util::ReadFile(req._path,&Body))
    {
        response = "HTTP/1.0 200 OK"+SEP;
        response += "Content-Length: " + std::to_string(Body.size()) + SEP;
        response += GetContentType(req._suffix);
        response += "Set-Cookie: sessionid=1234abcd" + SEP; //Cookie实验
        response += SEP;
        response += Body;
    }
    else if(req._path.find("baidu") != std::string::npos) //模拟重定向到百度
    {
        //重定向到百度
        response = "HTTP/1.0 301 Moved Permanently"+SEP;
        response += "Location: https://www.baidu.com/" + SEP;
        response += SEP;
    }
    else //404页面
    {
        response = "HTTP/1.0 404 Not Found"+SEP;
        Util::ReadFile(page_404,&Body);
        response += "Content-Length: " + std::to_string(Body.size()) + SEP;
        response += GetContentType(".html");
        response += SEP;
        response += Body;
    }



    return response;
}

int main(int argc,char* argv[])
{
    uint16_t port = 8088;
    if(argc == 2)
    {
        port = htons(atoi(argv[1]));
    }
    else if(argc > 2)
    {
        usage(argv[0]);
        exit(USAGE_ERR);
    }
    using namespace my_http;
    std::unique_ptr<HttpServer> hp(new HttpServer(HttpFunc,port));
    hp->Init();
    hp->Start();

    return 0;
}